﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lextm.SharpSnmpLib;
using Lextm.SharpSnmpLib.Messaging;
using System.Net;
using System.Text.RegularExpressions;

namespace devicesDll
{
    public class Printer : Device
    {
        #region Variables
        string serialNumber = null;
        string state = null;
        string paperStatus = null;
        string toner = null;
        string lifeCount = null;
        string tonerSupplyMaximum = null;
        string tonerSupplyLevel = null;
        string[,] paperInputDescription; 
        int snmpPort = 161;
    
        #endregion

        #region Constructor
        public Printer(string macAddress, IPAddress ip, string port)
        {
            this.mac = new string[1];
            this.mac[0] = macAddress;
            this.ip = ip;
            this.port = new string[1];
            this.port[0] = port;
        }
        #endregion

        #region Properties
        public string SerialNumber
        {
            get
            {
                return serialNumber;
            }
        }
        public string State
        {
            get
            {
                return state;
            }
        }
        public string PaperStatus
        {
            get
            {
                return paperStatus;
            }
        }
        public string Toner
        {
            get
            {
                return toner;
            }
        }
        public string LifeCount
        {
            get
            {
                return lifeCount;
            }
        }
        public string TonerSupplyMaximum
        {
            get
            {
                return tonerSupplyMaximum;
            }
        }
        public string TonerSupplyLevel
        {
            get
            {
                return tonerSupplyLevel;
            }
        }
        public string PaperInputDescription
        {
            get
            {
                string ret = "";
                for (int i = 0; i < paperInputDescription.Length/3; i++)
                {
                    for (int n = 0; n < 3; n++)
                    {
                        ret += paperInputDescription[i, n] + ";";
                    }
                    ret.Remove(ret.Length - 1);
                    ret += "\n";
                }
                return ret;
            }
        }
        public long RoomNumberActual
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }
        public int SnmpPort
        {
            get
            {
                return snmpPort;
            }
            set
            {
                snmpPort = value; 
            }
        }
        #endregion 

        #region Methods
        /// <summary>
        /// Make a request of a printer
        /// </summary>
        /// <param name="switchOnly">has to be false</param>
        /// <param name="query">the query for the request</param>
        public override void Query(bool switchOnly, string query)
        {
            if (this.ip == null)
            {
                connectionFailed = true;
                return;
            }
            connectionFailed = false;
            if (!switchOnly)    //if switch only do nothing     
            {
                string [] splitquery = query.Split(';');        //splits the querry 
                List<Variable> oids = new List<Variable>();         

                foreach (string request in splitquery)          //for each OID 
                {
                    if (request == "default")                   //if the string is default make a standard request
                        StandardRequest();
                    else
                    {
                        oids.Add(new Variable(new ObjectIdentifier(request)));  //else add the OID to oids list
                    }
                }
                if (oids.Count() != 0)      //if the oid list contains a oid, make the request 
                {
                    Request(ip, oids);      //make the request
                }
            } 
        }

        public override string ToString()
        {
            string ipstr;
            if (this.ip == null)
                ipstr = "null";
            else
                ipstr = this.ip.ToString();

            return "Printer\n IP: " + ipstr + "\n Mac: " + this.mac[0] + "\n";
        }

        private void Request(IPAddress ip, List<Variable> oids)  //make the request of custom querries
        {
            try
            {
                var result = Messenger.Get(VersionCode.V1,      //send the request
                new IPEndPoint(ip, snmpPort),
                new OctetString("public"),
                oids,
                timeout);

                for (int i = 0; i < result.Count; i++)      //for each result make a customResult
                {
                    customResults.Add(new CustomResult(oids[i].Id.ToString(), result[i].Data));
                }
            }
            catch (Lextm.SharpSnmpLib.Messaging.TimeoutException)     //if a timeoutexepetion occurs set connectionfailed 
            {
                connectionFailed = true;
            }
            catch (SnmpException ex)    //if a oid don't work
            {
                int x = 0;              //filters the index of the oid list
                Regex regex = new Regex(    
                    @"(?<wort>\bIndex\b):.(?<number>\d*)",
                    RegexOptions.IgnoreCase
                    | RegexOptions.Multiline
                    | RegexOptions.IgnorePatternWhitespace
                    | RegexOptions.Compiled
                    );
                Match match = regex.Match(ex.ToString());
                if (match.Success)
                    x = Convert.ToInt32(match.Groups["number"].ToString()) - 1;
                customResults.Add(new CustomResult(oids[x].Id.ToString(), "Error: " + oids[x].Id.ToString() + "doesn't work")); //set the error to the special oid 
                oids.RemoveAt(x);   //remove the oid
                Request(ip, oids);  //make a new request without the error oid
            }
            //catch                                           //if the request dont work return the error for the custom result
            //{
            //    customResults.Add(new CustomResult("all custom OIDS", "Error the Custom OIDS for printer don't work"));
            //}
        }

        private void StandardRequest()          //make the standard request  
        {
            PrinterCommands oids = new PrinterCommands();                       //new oid List with the standard oids
            List<Variable> printoptions = new List<Variable>();
            printoptions.Add(new Variable(new ObjectIdentifier(oids["Toner"])));
            printoptions.Add(new Variable(new ObjectIdentifier(oids["SerialNumber"])));
            printoptions.Add(new Variable(new ObjectIdentifier(oids["State"])));
            printoptions.Add(new Variable(new ObjectIdentifier(oids["LifeCount"])));
            printoptions.Add(new Variable(new ObjectIdentifier(oids["SupplyMaximum"])));
            printoptions.Add(new Variable(new ObjectIdentifier(oids["SupplyLevel"])));

            try                                     //Make the whole standardrequest at a printer
            {
                var testGet = Messenger.Get(VersionCode.V1, 
                                      new IPEndPoint(ip, snmpPort),
                                      new OctetString("public"),
                                      printoptions,
                                      timeout);
                
                var inputDescription = new List<Variable>();        //make a walk to get the infos about the paper trays of the printer
                Messenger.Walk(VersionCode.V1,
                               new IPEndPoint(ip, snmpPort),
                               new OctetString("public"),
                               new ObjectIdentifier(oids["InputDescription"]),
                               inputDescription,
                               timeout,
                               WalkMode.WithinSubtree);

                var paperMax = new List<Variable>();
                Messenger.Walk(VersionCode.V1,
                               new IPEndPoint(ip, snmpPort),
                               new OctetString("public"),
                               new ObjectIdentifier(oids["PaperMax"]),
                               paperMax,
                               timeout,
                               WalkMode.WithinSubtree);

                var paperCurrentLevel = new List<Variable>();
                Messenger.Walk(VersionCode.V1,
                               new IPEndPoint(ip, snmpPort),
                               new OctetString("public"),
                               new ObjectIdentifier(oids["PaperCurrentLevel"]),
                               paperCurrentLevel,
                               timeout,
                               WalkMode.WithinSubtree);

                toner = testGet[0].Data.ToString();             //saves the results on the properties
                serialNumber = testGet[1].Data.ToString();
                state = testGet[2].Data.ToString();
                lifeCount = testGet[3].Data.ToString();
                tonerSupplyMaximum = testGet[4].Data.ToString();
                tonerSupplyLevel = testGet[5].Data.ToString();


                paperInputDescription = new string[inputDescription.Count(), 3];        
                for (int i = 0; i < inputDescription.Count(); i++)
                {
                    paperInputDescription[i, 0] = inputDescription[i].Data.ToString();
                    paperInputDescription[i, 1] = paperMax[i].Data.ToString();
                    paperInputDescription[i, 2] = paperCurrentLevel[i].Data.ToString();
                }  
            }
            catch (Exception)
            {
                connectionFailed = true;
            }
            

        }
        #endregion
    }
}
